Introduction

RNA-seq was run on 36 ovarian cancer cell lines, each in singlicate.

All 36 cell lines have 72h cisplatin IC50s determined by Kristin Adams and Kendra Wendt in the Lang Lab.

Cisplatin IC50s

Add in links to Lab notebooks for IC50, RNAseq sample prep

Inputs

Inputs consisted of:

DESeq2

To determine genes differentially expressed between cisplatin sensitive and resistant cell lines, we used the median cisplatin IC50 of all 36 cell lines as a cut-point, and excluded cell lines within +/- one standard deviation of the median. These were defined in the metadata table.

Read in metadata table

as.data.frame(read_excel("Metadata3.xlsx")) -> metadata
row.names(metadata) <- metadata$files
metadata

Load count matrix

countmatrix <- as.matrix(read.delim("../star_salmon/salmon.merged.gene_counts.tsv", sep="\t", row.names="gene_id"))
countmatrix <- countmatrix[,-1]
countmatrix2 <- matrix(as.numeric(countmatrix), ncol = ncol(countmatrix), dimnames = list(rownames(countmatrix), colnames(countmatrix)))
countmatrix2 <- round(countmatrix2)
countmatrix2 <- countmatrix2[,rownames(metadata)]
head(countmatrix2)
         X16 X29  X14 X22 X21  X25 X20 X19 X28 X23 X27 X18 X31 X30   X17 X15   X2 X32 X13  X6 X11 X36
A1BG      28  21   52  45  48   39   8  66  20  36   0  52   2   4    27  54    0  16  37  26  14  35
A1BG-AS1  62  54  108  80  88   66  38  67  54  67   0  36  15   6   107  82    0  34  80 109  50  67
A1CF       1   2    0   0   0    2   0   0   0   0   0   0   0   0     0   0 7003   1   0   1   0   1
A2M       11  26 1161   0  10 8791   1   1  16   0   0   0   7  23 11639   0 8292   1  11   0   0   5
A2M-AS1   10   0   15  11  99    3   1  23   8  14  34  10  52   8     4   1    2  10   5  10   5   0
A2ML1      0  74    7  47   2   23   2   0   0   6   0   0   0   9    20   0    0  23   2   0  41  10
         X10 X5 X8 X9 X24 X33 X34 X35 X26  X1   X12  X4 X3 X7
A1BG      14 30  2 32   4   1   9  14   4 137    30  58  0  0
A1BG-AS1  13 28 18 64  20   9  27  29   1  88    65 107  0  0
A1CF       0  0  0  0   0   0   0   0   0   0     0   0  0  0
A2M        0 38  0  0   0 113   3  89   0   0 11343   0  3  0
A2M-AS1    0  4  4 19  21  26  78  94   2   5    15   2  0  0
A2ML1      0  0  6  0   0  21   4   7   1   0     0   0  0  0

Create DESeqDataSet object dds

dds <- DESeqDataSetFromMatrix(countData = countmatrix2, colData = metadata, design = ~ Subtype + PlatinumSensitivity)
converting counts to integer mode
Warning: some variables in design formula are characters, converting to factors

Pre-filtering

This step removes genes with low expression to increase multiple comparison power.

keep <- rowSums(counts(dds)) >= 500
dds <- dds[keep,]
nrow(dds)
[1] 15763

Run DESeq2

dds <- DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
58 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest

Filter DESeq2 results for significant genes

Filter res for padj < 0.05 and |log2FC| >= 1.2

res.filtered <- as.data.frame(res) %>%
  filter(padj<0.05)%>%
  filter(log2FoldChange >= 1.2 | log2FoldChange <= -1.2)
res.filtered

Data QC

Data transformation

Here we performed normal transformation [log2(n+1)], variance stabilized transformation, and regularized log tranformation to improve visualization of the data values. To speed up subsequent re-runs, we have hidden analysis for non-vst.

# ntd <- normTransform(dds)
#meanSdPlot(assay(ntd))
vsd <- vst(dds)
meanSdPlot(assay(vsd))

# rld <- rlog(dds)
# meanSdPlot(assay(rld))

Based on this data, variance-stabilized tranformation lead to the lowest standard deviation between samples and was mostly located towards the high expression transcripts, as might be expected.

PCA plot

pcaData <- plotPCA(vsd, intgroup=c("Subtype", "PlatinumSensitivity","CellLine"), returnData=TRUE)
percentVar <- round(100 * attr(pcaData, "percentVar"))
myColors <- c("#76AB7E", "#63E678", "#1D32FB", "#7B87FD", "#01BD1F", "#E8A426", "#0B7C1D", "#BB19E7")
names(myColors) <- levels(pcaData$Subtype)
colScale <- scale_colour_manual(name = "Subtype",values = myColors)
pca <- ggplot(pcaData, aes(PC1, PC2, color=Subtype, shape=PlatinumSensitivity, label=CellLine)) +
  geom_point(size=3) +
  geom_text(hjust=0, vjust=0) +
  xlab(paste0("PC1: ",percentVar[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar[2],"% variance")) +
  coord_fixed() +
  theme_classic() + 
  colScale
pca
ggsave("pca.pdf", pca)
Saving 7.29 x 4.51 in image

PCA plot groups samples roughly by subtype

Sample-wise correlation

vsd.mod <- vsd.df 
colnames(vsd.mod) <- metadata$CellLine[match(colnames(vsd.mod), metadata$files)]
vsd.mod$gene <- row.names(vsd.mod)

corr <- vsd.mod %>%
  select(-gene) %>%
  cor(method = "spearman")

df.mod <- df
row.names(df.mod) <- metadata$CellLine[match(row.names(df.mod), metadata$files)]

pheatmap(corr, annotation_col=df.mod)

Barnes RF approach?

Contacted PI 10/27/2022 because script is not on github. No response as of 12/16/2022.

Plot heatmaps to check sample to sample variability

Plotting the top 100 most highly expressed genes:

select <- order(rowMeans(counts(dds,normalized=TRUE)),
                decreasing=TRUE)[1:100]
df <- as.data.frame(colData(dds)[,c("Subtype", "PlatinumSensitivity")])
pheatmap(assay(vsd)[select,], cluster_rows=FALSE, show_rownames=FALSE,
         labels_col=colData(dds)[,c("CellLine")],annotation_col=df)

Dendrogram based on gene expression

Pull genes contributing to principal components 1 & 2

TPM <- as.matrix(read.delim("../star_salmon/salmon.merged.gene_tpm.tsv", sep="\t", row.names="gene_id"))
TPM <- TPM[,-1]
TPM <- matrix(as.numeric(TPM), ncol = ncol(TPM), dimnames = list(rownames(TPM), colnames(TPM)))
TPM <- round(TPM)
TPM <- TPM[,rownames(metadata)]
TPM2 <- TPM
colnames(TPM2) <- metadata$CellLine[match(colnames(TPM2), metadata$files)]
TPM.log <- log(TPM+1)
PCA <- prcomp(TPM.log, scale=TRUE)
PCA.mat <- as.data.frame(PCA$x)
PCA.PC1filt <- PCA.mat %>% filter(PC1 < quantile(PCA.mat[,"PC1"], .2)[[1]])
TPM3 <- TPM2[rowSums(TPM2)>1000,]
counts.sc <- t(TPM3)
dist <- dist(counts.sc)
clust <- hclust(dist, method="average")
dend <- as.dendrogram(clust)
par(mar=c(10,2,1,1))
my_colors <- ifelse(metadata$Subtype=="HGSC", "red", 
                    ifelse(metadata$Subtype=="LGSC", "blue", 
                           ifelse(metadata$Subtype=="OCCC", "yellow", 
                                  ifelse(metadata$Subtype=="EC", "green",
                                         ifelse(metadata$Subtype=="SCCOHT","purple", 
                                                ifelse(metadata$Subtype=="MUC","orange","white"))))))
plot(dend)
colored_bars(colors = my_colors, dend = dend, rowLabels = "Subtype")

I tried a lot of different iterations of this (including: various cutoffs for variance of genes, genes contributing most to first and second principal components, more highly expressed genes, TPM vs vst data, clustering methods), but the fundamental problem is that isogenic pairs rarely cluster anywhere near each other, even though the PCA analysis shows this relationship. I don’t know that this is a reliable method for determining relatedness/subtyping, unless a robust gene set is developed.

Data visualization

Plot Heatmap of top differentially expressed genes

vsd.df <-as.data.frame(assay(vsd))
pheatmap(vsd.df[rownames(res.filtered),], labels_col=colData(dds)[,c("CellLine")],annotation_col=df, color=colorRampPalette(c("white", "red"))(50))

Heatmap based on TPM

pheatmap(TPM.log[rownames(res.filtered),], labels_col=colData(dds)[,c("CellLine")], annotation_col=df, color=colorRampPalette(c("white", "red"))(10))

Heatmap with mean-centered data

center_scale <- function(x) {
  scale(x, scale=FALSE)
}
vsd.meancenter <- apply(vsd.df, 1, center_scale)
vsd.meancenter <-t(vsd.meancenter)
colnames(vsd.meancenter) <- colnames(vsd.df)
vsd.meancenter <- as.data.frame(vsd.meancenter) 
color <- colorRampPalette(brewer.pal(11, "PuOr"))(50)
myBreaks <- c(seq(min(vsd.meancenter[rownames(res.filtered),]), 0, length.out=ceiling(50/2) + 1), 
              seq(max(vsd.meancenter[rownames(res.filtered),])/50, max(vsd.meancenter[rownames(res.filtered),]), length.out=floor(50/2)))
pheatmap(vsd.meancenter[rownames(res.filtered),], labels_col=colData(dds)[,c("CellLine")], color=color, border_color = NA, annotation_col = df, breaks=myBreaks)

Volcano Plots

res.filtered %>% 
  ggplot(aes(x=log2FoldChange, y=-log10(pvalue), label=rownames(res.filtered))) +
  geom_point() +
  theme_minimal() +
  scale_color_manual(values = c("black", "blue", "red"))+
  geom_text_repel()

Run Gene Ontology

Re-run DESeq using IC50 as continuous variable

Create DESeqDataSet object dds

dds2 <- DESeqDataSetFromMatrix(countData = countmatrix2, colData = metadata, design = ~ Subtype + IC50)
converting counts to integer mode
Warning: some variables in design formula are characters, converting to factors  the design formula contains one or more numeric variables that have mean or
  standard deviation larger than 5 (an arbitrary threshold to trigger this message).
  Including numeric variables with large mean can induce collinearity with the intercept.
  Users should center and scale numeric variables in the design to improve GLM convergence.

Pre-filtering

This step removes genes with low expression to increase multiple comparison power.

keep <- rowSums(counts(dds2)) >= 100
dds2 <- dds2[keep,]
nrow(dds2)
[1] 18308

Run DESeq2

dds2 <- DESeq(dds2)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
875 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest

Filter DESeq2 results for significant genes

Filter res for padj < 0.05 and |log2FC| >= 1.2

res.2.filtered <- as.data.frame(res2) %>%
  filter(padj<0.05)%>%
  filter(log2FoldChange >= 1.2 | log2FoldChange <= -1.2)
res.2.filtered

Data QC

Data transformation

vsd2 <- vst(dds2)
meanSdPlot(assay(vsd2))

PCA plot

pcaData2 <- plotPCA(vsd2, intgroup=c("Subtype", "PlatinumSensitivity","CellLine"), returnData=TRUE)
percentVar2 <- round(100 * attr(pcaData2, "percentVar"))
pca2 <- ggplot(pcaData2, aes(PC1, PC2, color=Subtype, shape=PlatinumSensitivity, label=CellLine)) +
  geom_point(size=3) +
  geom_text(hjust=0, vjust=0) +
  xlab(paste0("PC1: ",percentVar2[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar2[2],"% variance")) +
  coord_fixed() +
  theme_classic() +
  colScale
pca2
ggsave("pca_IC50.pdf", pca2)
Saving 7.29 x 4.51 in image

Data visualization

Plot Heatmap of top differentially expressed genes

vsd2.df <-as.data.frame(assay(vsd2))
color <- colorRampPalette(c("white", "red"))(40)
breaks <- seq(6,12,length.out=40)  
pheatmap(vsd2.df[rownames(res.2.filtered),], labels_col=colData(dds2)[,c("CellLine")],annotation_col=df, color=color, breaks=breaks)

Heatmap with mean-centered data

vsd2.meancenter <- apply(vsd2.df, 1, center_scale)
vsd2.meancenter <-t(vsd2.meancenter)
colnames(vsd2.meancenter) <- colnames(vsd2.df)
vsd2.meancenter <- as.data.frame(vsd2.meancenter) 
color <- colorRampPalette(brewer.pal(11, "PuOr"))(50)
myBreaks2 <- c(seq(min(vsd2.meancenter[rownames(res.2.filtered),]), 0, length.out=ceiling(50/2) + 1), 
              seq(max(vsd2.meancenter[rownames(res.2.filtered),])/50, max(vsd2.meancenter[rownames(res.2.filtered),]), length.out=floor(50/2)))
pheatmap(vsd2.meancenter[rownames(res.2.filtered),], labels_col=colData(dds2)[,c("CellLine")], color=color, border_color = NA, annotation_col = df, breaks=myBreaks2)

Volcano Plots

res.2.filtered %>% 
  ggplot(aes(x=log2FoldChange, y=-log10(pvalue), label=rownames(res.2.filtered))) +
  geom_point() +
  theme_minimal() +
  scale_color_manual(values = c("black", "blue", "red"))+
  geom_text_repel()

Heatmap of genes involved in cisplatin resistance

Plot heatmap of genes annotated as involved in cisplatin resistance in PMID: 34645978

resist.genes <- read.delim("ResistanceGenes.txt", header = FALSE)
resist.genes <- resist.genes$V1
pheatmap(TPM.log[resist.genes[resist.genes %in% row.names(TPM.log)],], labels_col=colData(dds)[,c("CellLine")],annotation_col=df, color=colorRampPalette(c("white", "red"))(50))

res2.resist <- res2[resist.genes[resist.genes %in% row.names(res2)],c("log2FoldChange","padj")]
res2.resist <- as.data.frame(res2.resist) %>%
  filter(padj < 0.05)
res2.resist

Heatmap with mean-centered data

myBreaks3 <- c(seq(min(vsd.meancenter[resist.genes[resist.genes %in% row.names(vsd.meancenter)],]), 0, length.out=ceiling(50/2) + 1), 
              seq(max(vsd.meancenter[resist.genes[resist.genes %in% row.names(vsd.meancenter)],])/50, max(vsd.meancenter[resist.genes[resist.genes %in% row.names(vsd.meancenter)],]), length.out=floor(50/2)))
pheatmap(vsd.meancenter[resist.genes[resist.genes %in% row.names(vsd.meancenter)],], labels_col=colData(dds)[,c("CellLine")],annotation_col=df, color=color, border_color = NA, breaks=myBreaks3)

Package versions

Figure out how to print all package versions used.

LS0tCnRpdGxlOiAiT3ZhcmlhbiBDYW5jZXIgQ2VsbCBMaW5lIFJOQXNlcSBQbGF0aW51bSBTZW5zaXRpdml0eSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgSW50cm9kdWN0aW9uICAKClJOQS1zZXEgd2FzIHJ1biBvbiAzNiBvdmFyaWFuIGNhbmNlciBjZWxsIGxpbmVzLCBlYWNoIGluIHNpbmdsaWNhdGUuICAKCkFsbCAzNiBjZWxsIGxpbmVzIGhhdmUgNzJoIGNpc3BsYXRpbiBJQzUwcyBkZXRlcm1pbmVkIGJ5IEtyaXN0aW4gQWRhbXMgYW5kIEtlbmRyYSAKV2VuZHQgaW4gdGhlIExhbmcgTGFiLiAKCiFbQ2lzcGxhdGluIElDNTBzXShDaXNwbGF0aW5JQzUwLmpwZyl7aGVpZ2h0PTUwJSwgd2lkdGg9NTAlfQoKQWRkIGluIGxpbmtzIHRvIExhYiBub3RlYm9va3MgZm9yIElDNTAsIFJOQXNlcSBzYW1wbGUgcHJlcAoKIyMgSW5wdXRzCgpJbnB1dHMgY29uc2lzdGVkIG9mOiAgCgoqIE1ldGFkYXRhIHNwcmVhZHNoZWV0ICAKKiBzYWxtb24ubWVyZ2VkLmdlbmVfY291bnRzLnRzdiBmaWxlIGZyb20gbmYtY29yZS9ybmFzZXEgcGlwZWxpbmUgb3V0cHV0ICAKKiBOZWNlc3NhcnkgcGFja2FnZXMgIAoKYGBge3IgbG9hZCBwYWNrYWdlcywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KERFU2VxMikKbGlicmFyeSh2c24pCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoZGVuZGV4dGVuZCkKYGBgCgojIyBERVNlcTIKClRvIGRldGVybWluZSBnZW5lcyBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2VlbiBjaXNwbGF0aW4gc2Vuc2l0aXZlIGFuZCByZXNpc3RhbnQgY2VsbCBsaW5lcywgd2UgdXNlZCB0aGUgbWVkaWFuIGNpc3BsYXRpbiBJQzUwIG9mIGFsbCAzNiBjZWxsIGxpbmVzIGFzIGEgY3V0LXBvaW50LCBhbmQgZXhjbHVkZWQgY2VsbCBsaW5lcyB3aXRoaW4gKy8tIG9uZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIG1lZGlhbi4gVGhlc2Ugd2VyZSBkZWZpbmVkIGluIHRoZSBtZXRhZGF0YSB0YWJsZS4KCiMjIyBSZWFkIGluIG1ldGFkYXRhIHRhYmxlCgpgYGB7ciBsb2FkIG1ldGF0YWJsZX0KYXMuZGF0YS5mcmFtZShyZWFkX2V4Y2VsKCJNZXRhZGF0YTMueGxzeCIpKSAtPiBtZXRhZGF0YQpyb3cubmFtZXMobWV0YWRhdGEpIDwtIG1ldGFkYXRhJGZpbGVzCm1ldGFkYXRhCmBgYAojIyMgTG9hZCBjb3VudCBtYXRyaXgKCmBgYHtyIHJlYWQgY291bnQgbWF0cml4fQpjb3VudG1hdHJpeCA8LSBhcy5tYXRyaXgocmVhZC5kZWxpbSgiLi4vc3Rhcl9zYWxtb24vc2FsbW9uLm1lcmdlZC5nZW5lX2NvdW50cy50c3YiLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzPSJnZW5lX2lkIikpCmNvdW50bWF0cml4IDwtIGNvdW50bWF0cml4WywtMV0KY291bnRtYXRyaXgyIDwtIG1hdHJpeChhcy5udW1lcmljKGNvdW50bWF0cml4KSwgbmNvbCA9IG5jb2woY291bnRtYXRyaXgpLCBkaW1uYW1lcyA9IGxpc3Qocm93bmFtZXMoY291bnRtYXRyaXgpLCBjb2xuYW1lcyhjb3VudG1hdHJpeCkpKQpjb3VudG1hdHJpeDIgPC0gcm91bmQoY291bnRtYXRyaXgyKQpjb3VudG1hdHJpeDIgPC0gY291bnRtYXRyaXgyWyxyb3duYW1lcyhtZXRhZGF0YSldCmhlYWQoY291bnRtYXRyaXgyKQpgYGAKIyMjIENyZWF0ZSBERVNlcURhdGFTZXQgb2JqZWN0IGRkcwoKYGBge3IgREVTZXFEYXRhU2V0IGdlbmVyYXRpb259CmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGNvdW50bWF0cml4MiwgY29sRGF0YSA9IG1ldGFkYXRhLCBkZXNpZ24gPSB+IFN1YnR5cGUgKyBQbGF0aW51bVNlbnNpdGl2aXR5KQpgYGAKIyMjIFByZS1maWx0ZXJpbmcKVGhpcyBzdGVwIHJlbW92ZXMgZ2VuZXMgd2l0aCBsb3cgZXhwcmVzc2lvbiB0byBpbmNyZWFzZSBtdWx0aXBsZSBjb21wYXJpc29uIHBvd2VyLgoKYGBge3J9CmtlZXAgPC0gcm93U3Vtcyhjb3VudHMoZGRzKSkgPj0gNTAwCmRkcyA8LSBkZHNba2VlcCxdCm5yb3coZGRzKQpgYGAKCgojIyMgUnVuIERFU2VxMiAKYGBge3IgREVTZXEyfQpkZHMgPC0gREVTZXEoZGRzKQpgYGAKCiMjIyBQcmludCBERVNlcSByZXN1bHRzCmBgYHtyIGNyZWF0ZSByZXN1bHRzIHRhYmxlfQpyZXMgPC0gcmVzdWx0cyhkZHMsIGNvbnRyYXN0PWMoIlBsYXRpbnVtU2Vuc2l0aXZpdHkiLCAicmVzaXN0YW50IiwgInNlbnNpdGl2ZSIpKQpyZXMKd3JpdGUuY3N2KGFzLmRhdGEuZnJhbWUocmVzKSwgZmlsZSA9ICJERVNlcS5jc3YiKQpgYGAKCiMjIyBGaWx0ZXIgREVTZXEyIHJlc3VsdHMgZm9yIHNpZ25pZmljYW50IGdlbmVzCkZpbHRlciByZXMgZm9yIHBhZGogPCAwLjA1IGFuZCB8bG9nMkZDfCA+PSAxLjIKYGBge3IgZmlsdGVyIHJlc30KcmVzLmZpbHRlcmVkIDwtIGFzLmRhdGEuZnJhbWUocmVzKSAlPiUKICBmaWx0ZXIocGFkajwwLjA1KSU+JQogIGZpbHRlcihsb2cyRm9sZENoYW5nZSA+PSAxLjIgfCBsb2cyRm9sZENoYW5nZSA8PSAtMS4yKQpyZXMuZmlsdGVyZWQKYGBgCiMjIERhdGEgUUMKCiMjIyBEYXRhIHRyYW5zZm9ybWF0aW9uIApIZXJlIHdlIHBlcmZvcm1lZCBub3JtYWwgdHJhbnNmb3JtYXRpb24gW2xvZzIobisxKV0sIHZhcmlhbmNlIHN0YWJpbGl6ZWQgdHJhbnNmb3JtYXRpb24sIGFuZCByZWd1bGFyaXplZCBsb2cgdHJhbmZvcm1hdGlvbiB0byBpbXByb3ZlIHZpc3VhbGl6YXRpb24gb2YgdGhlIGRhdGEgdmFsdWVzLiBUbyBzcGVlZCB1cCBzdWJzZXF1ZW50IHJlLXJ1bnMsIHdlIGhhdmUgaGlkZGVuIGFuYWx5c2lzIGZvciBub24tdnN0LgoKYGBge3Igbm9ybSB0cmFuc2Zvcm1hdGlvbiBhbmQgc3RkZXYgcGxvdH0KIyBudGQgPC0gbm9ybVRyYW5zZm9ybShkZHMpCiNtZWFuU2RQbG90KGFzc2F5KG50ZCkpCmBgYAoKCmBgYHtyIHZhciBzdGFiIHRyYW5zZm9ybWF0aW9uIGFuZCBzdGRldiBwbG90fQp2c2QgPC0gdnN0KGRkcykKbWVhblNkUGxvdChhc3NheSh2c2QpKQpgYGAKCgpgYGB7ciByZWcgbG9nIHRyYW5zZm9ybWF0aW9uIGFuZCBzdGRldiBwbG90fQojIHJsZCA8LSBybG9nKGRkcykKIyBtZWFuU2RQbG90KGFzc2F5KHJsZCkpCmBgYAoKQmFzZWQgb24gdGhpcyBkYXRhLCB2YXJpYW5jZS1zdGFiaWxpemVkIHRyYW5mb3JtYXRpb24gbGVhZCB0byB0aGUgbG93ZXN0IHN0YW5kYXJkIGRldmlhdGlvbiBiZXR3ZWVuIHNhbXBsZXMgYW5kIHdhcyBtb3N0bHkgbG9jYXRlZCB0b3dhcmRzIHRoZSBoaWdoIGV4cHJlc3Npb24gdHJhbnNjcmlwdHMsIGFzIG1pZ2h0IGJlIGV4cGVjdGVkLgoKIyMjIFBDQSBwbG90CmBgYHtyIHZzZCBQQ0F9CnBjYURhdGEgPC0gcGxvdFBDQSh2c2QsIGludGdyb3VwPWMoIlN1YnR5cGUiLCAiUGxhdGludW1TZW5zaXRpdml0eSIsIkNlbGxMaW5lIiksIHJldHVybkRhdGE9VFJVRSkKcGVyY2VudFZhciA8LSByb3VuZCgxMDAgKiBhdHRyKHBjYURhdGEsICJwZXJjZW50VmFyIikpCm15Q29sb3JzIDwtIGMoIiM3NkFCN0UiLCAiIzYzRTY3OCIsICIjMUQzMkZCIiwgIiM3Qjg3RkQiLCAiIzAxQkQxRiIsICIjRThBNDI2IiwgIiMwQjdDMUQiLCAiI0JCMTlFNyIpCm5hbWVzKG15Q29sb3JzKSA8LSBsZXZlbHMocGNhRGF0YSRTdWJ0eXBlKQpjb2xTY2FsZSA8LSBzY2FsZV9jb2xvdXJfbWFudWFsKG5hbWUgPSAiU3VidHlwZSIsdmFsdWVzID0gbXlDb2xvcnMpCnBjYSA8LSBnZ3Bsb3QocGNhRGF0YSwgYWVzKFBDMSwgUEMyLCBjb2xvcj1TdWJ0eXBlLCBzaGFwZT1QbGF0aW51bVNlbnNpdGl2aXR5LCBsYWJlbD1DZWxsTGluZSkpICsKICBnZW9tX3BvaW50KHNpemU9MykgKwogIGdlb21fdGV4dChoanVzdD0wLCB2anVzdD0wKSArCiAgeGxhYihwYXN0ZTAoIlBDMTogIixwZXJjZW50VmFyWzFdLCIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLHBlcmNlbnRWYXJbMl0sIiUgdmFyaWFuY2UiKSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArIAogIGNvbFNjYWxlCnBjYQpnZ3NhdmUoInBjYS5wZGYiLCBwY2EpCmBgYApQQ0EgcGxvdCBncm91cHMgc2FtcGxlcyByb3VnaGx5IGJ5IHN1YnR5cGUKCiMjIyBTYW1wbGUtd2lzZSBjb3JyZWxhdGlvbgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPSA4fQp2c2QubW9kIDwtIHZzZC5kZiAKY29sbmFtZXModnNkLm1vZCkgPC0gbWV0YWRhdGEkQ2VsbExpbmVbbWF0Y2goY29sbmFtZXModnNkLm1vZCksIG1ldGFkYXRhJGZpbGVzKV0KdnNkLm1vZCRnZW5lIDwtIHJvdy5uYW1lcyh2c2QubW9kKQoKY29yciA8LSB2c2QubW9kICU+JQogIHNlbGVjdCgtZ2VuZSkgJT4lCiAgY29yKG1ldGhvZCA9ICJzcGVhcm1hbiIpCgpkZi5tb2QgPC0gZGYKcm93Lm5hbWVzKGRmLm1vZCkgPC0gbWV0YWRhdGEkQ2VsbExpbmVbbWF0Y2gocm93Lm5hbWVzKGRmLm1vZCksIG1ldGFkYXRhJGZpbGVzKV0KCnBoZWF0bWFwKGNvcnIsIGFubm90YXRpb25fY29sPWRmLm1vZCkKYGBgCgojIyMgQmFybmVzIFJGIGFwcHJvYWNoPwpDb250YWN0ZWQgUEkgMTAvMjcvMjAyMiBiZWNhdXNlIHNjcmlwdCBpcyBub3Qgb24gZ2l0aHViLiBObyByZXNwb25zZSBhcyBvZiAxMi8xNi8yMDIyLgoKCiMjIyBQbG90IGhlYXRtYXBzIHRvIGNoZWNrIHNhbXBsZSB0byBzYW1wbGUgdmFyaWFiaWxpdHkKUGxvdHRpbmcgdGhlIHRvcCAxMDAgbW9zdCBoaWdobHkgZXhwcmVzc2VkIGdlbmVzOgpgYGB7ciBoZWF0bWFwc30Kc2VsZWN0IDwtIG9yZGVyKHJvd01lYW5zKGNvdW50cyhkZHMsbm9ybWFsaXplZD1UUlVFKSksCiAgICAgICAgICAgICAgICBkZWNyZWFzaW5nPVRSVUUpWzE6MTAwXQpkZiA8LSBhcy5kYXRhLmZyYW1lKGNvbERhdGEoZGRzKVssYygiU3VidHlwZSIsICJQbGF0aW51bVNlbnNpdGl2aXR5IildKQpwaGVhdG1hcChhc3NheSh2c2QpW3NlbGVjdCxdLCBjbHVzdGVyX3Jvd3M9RkFMU0UsIHNob3dfcm93bmFtZXM9RkFMU0UsCiAgICAgICAgIGxhYmVsc19jb2w9Y29sRGF0YShkZHMpWyxjKCJDZWxsTGluZSIpXSxhbm5vdGF0aW9uX2NvbD1kZikKYGBgCiMjIyBEZW5kcm9ncmFtIGJhc2VkIG9uIGdlbmUgZXhwcmVzc2lvbgpQdWxsIGdlbmVzIGNvbnRyaWJ1dGluZyB0byBwcmluY2lwYWwgY29tcG9uZW50cyAxICYgMgpgYGB7cn0KVFBNIDwtIGFzLm1hdHJpeChyZWFkLmRlbGltKCIuLi9zdGFyX3NhbG1vbi9zYWxtb24ubWVyZ2VkLmdlbmVfdHBtLnRzdiIsIHNlcD0iXHQiLCByb3cubmFtZXM9ImdlbmVfaWQiKSkKVFBNIDwtIFRQTVssLTFdClRQTSA8LSBtYXRyaXgoYXMubnVtZXJpYyhUUE0pLCBuY29sID0gbmNvbChUUE0pLCBkaW1uYW1lcyA9IGxpc3Qocm93bmFtZXMoVFBNKSwgY29sbmFtZXMoVFBNKSkpClRQTSA8LSByb3VuZChUUE0pClRQTSA8LSBUUE1bLHJvd25hbWVzKG1ldGFkYXRhKV0KVFBNMiA8LSBUUE0KY29sbmFtZXMoVFBNMikgPC0gbWV0YWRhdGEkQ2VsbExpbmVbbWF0Y2goY29sbmFtZXMoVFBNMiksIG1ldGFkYXRhJGZpbGVzKV0KVFBNLmxvZyA8LSBsb2coVFBNKzEpClBDQSA8LSBwcmNvbXAoVFBNLmxvZywgc2NhbGU9VFJVRSkKUENBLm1hdCA8LSBhcy5kYXRhLmZyYW1lKFBDQSR4KQpQQ0EuUEMxZmlsdCA8LSBQQ0EubWF0ICU+JSBmaWx0ZXIoUEMxIDwgcXVhbnRpbGUoUENBLm1hdFssIlBDMSJdLCAuMilbWzFdXSkKYGBgCgoKYGBge3J9ClRQTTMgPC0gVFBNMltyb3dTdW1zKFRQTTIpPjEwMDAsXQpjb3VudHMuc2MgPC0gdChUUE0zKQpkaXN0IDwtIGRpc3QoY291bnRzLnNjKQpjbHVzdCA8LSBoY2x1c3QoZGlzdCwgbWV0aG9kPSJhdmVyYWdlIikKZGVuZCA8LSBhcy5kZW5kcm9ncmFtKGNsdXN0KQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTB9CnBhcihtYXI9YygxMCwyLDEsMSkpCm15X2NvbG9ycyA8LSBpZmVsc2UobWV0YWRhdGEkU3VidHlwZT09IkhHU0MiLCAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG1ldGFkYXRhJFN1YnR5cGU9PSJMR1NDIiwgImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG1ldGFkYXRhJFN1YnR5cGU9PSJPQ0NDIiwgInllbGxvdyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG1ldGFkYXRhJFN1YnR5cGU9PSJFQyIsICJncmVlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG1ldGFkYXRhJFN1YnR5cGU9PSJTQ0NPSFQiLCJwdXJwbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG1ldGFkYXRhJFN1YnR5cGU9PSJNVUMiLCJvcmFuZ2UiLCJ3aGl0ZSIpKSkpKSkKcGxvdChkZW5kKQpjb2xvcmVkX2JhcnMoY29sb3JzID0gbXlfY29sb3JzLCBkZW5kID0gZGVuZCwgcm93TGFiZWxzID0gIlN1YnR5cGUiKQpgYGAKSSB0cmllZCBhIGxvdCBvZiBkaWZmZXJlbnQgaXRlcmF0aW9ucyBvZiB0aGlzIChpbmNsdWRpbmc6IHZhcmlvdXMgY3V0b2ZmcyBmb3IgdmFyaWFuY2Ugb2YgZ2VuZXMsIGdlbmVzIGNvbnRyaWJ1dGluZyBtb3N0IHRvIGZpcnN0IGFuZCBzZWNvbmQgcHJpbmNpcGFsIGNvbXBvbmVudHMsIG1vcmUgaGlnaGx5IGV4cHJlc3NlZCBnZW5lcywgVFBNIHZzIHZzdCBkYXRhLCBjbHVzdGVyaW5nIG1ldGhvZHMpLCBidXQgdGhlIGZ1bmRhbWVudGFsIHByb2JsZW0gaXMgdGhhdCBpc29nZW5pYyBwYWlycyByYXJlbHkgY2x1c3RlciBhbnl3aGVyZSBuZWFyIGVhY2ggb3RoZXIsIGV2ZW4gdGhvdWdoIHRoZSBQQ0EgYW5hbHlzaXMgc2hvd3MgdGhpcyByZWxhdGlvbnNoaXAuIEkgZG9uJ3Qga25vdyB0aGF0IHRoaXMgaXMgYSByZWxpYWJsZSBtZXRob2QgZm9yIGRldGVybWluaW5nIHJlbGF0ZWRuZXNzL3N1YnR5cGluZywgdW5sZXNzIGEgcm9idXN0IGdlbmUgc2V0IGlzIGRldmVsb3BlZC4gCgojIyBEYXRhIHZpc3VhbGl6YXRpb24KCiMjIyBQbG90IEhlYXRtYXAgb2YgdG9wIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcwpgYGB7ciBwbG90IGhlYXRtYXAsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSA4fQp2c2QuZGYgPC1hcy5kYXRhLmZyYW1lKGFzc2F5KHZzZCkpCnBoZWF0bWFwKHZzZC5kZltyb3duYW1lcyhyZXMuZmlsdGVyZWQpLF0sIGxhYmVsc19jb2w9Y29sRGF0YShkZHMpWyxjKCJDZWxsTGluZSIpXSxhbm5vdGF0aW9uX2NvbD1kZiwgY29sb3I9Y29sb3JSYW1wUGFsZXR0ZShjKCJ3aGl0ZSIsICJyZWQiKSkoNTApKQpgYGAKIyMjIEhlYXRtYXAgYmFzZWQgb24gVFBNCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gOH0KcGhlYXRtYXAoVFBNLmxvZ1tyb3duYW1lcyhyZXMuZmlsdGVyZWQpLF0sIGxhYmVsc19jb2w9Y29sRGF0YShkZHMpWyxjKCJDZWxsTGluZSIpXSwgYW5ub3RhdGlvbl9jb2w9ZGYsIGNvbG9yPWNvbG9yUmFtcFBhbGV0dGUoYygid2hpdGUiLCAicmVkIikpKDEwKSkKYGBgCiMjIyBIZWF0bWFwIHdpdGggbWVhbi1jZW50ZXJlZCBkYXRhCmBgYHtyLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD04fQpjZW50ZXJfc2NhbGUgPC0gZnVuY3Rpb24oeCkgewogIHNjYWxlKHgsIHNjYWxlPUZBTFNFKQp9CnZzZC5tZWFuY2VudGVyIDwtIGFwcGx5KHZzZC5kZiwgMSwgY2VudGVyX3NjYWxlKQp2c2QubWVhbmNlbnRlciA8LXQodnNkLm1lYW5jZW50ZXIpCmNvbG5hbWVzKHZzZC5tZWFuY2VudGVyKSA8LSBjb2xuYW1lcyh2c2QuZGYpCnZzZC5tZWFuY2VudGVyIDwtIGFzLmRhdGEuZnJhbWUodnNkLm1lYW5jZW50ZXIpIApjb2xvciA8LSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoMTEsICJQdU9yIikpKDUwKQpteUJyZWFrcyA8LSBjKHNlcShtaW4odnNkLm1lYW5jZW50ZXJbcm93bmFtZXMocmVzLmZpbHRlcmVkKSxdKSwgMCwgbGVuZ3RoLm91dD1jZWlsaW5nKDUwLzIpICsgMSksIAogICAgICAgICAgICAgIHNlcShtYXgodnNkLm1lYW5jZW50ZXJbcm93bmFtZXMocmVzLmZpbHRlcmVkKSxdKS81MCwgbWF4KHZzZC5tZWFuY2VudGVyW3Jvd25hbWVzKHJlcy5maWx0ZXJlZCksXSksIGxlbmd0aC5vdXQ9Zmxvb3IoNTAvMikpKQpwaGVhdG1hcCh2c2QubWVhbmNlbnRlcltyb3duYW1lcyhyZXMuZmlsdGVyZWQpLF0sIGxhYmVsc19jb2w9Y29sRGF0YShkZHMpWyxjKCJDZWxsTGluZSIpXSwgY29sb3I9Y29sb3IsIGJvcmRlcl9jb2xvciA9IE5BLCBhbm5vdGF0aW9uX2NvbCA9IGRmLCBicmVha3M9bXlCcmVha3MpCmBgYAoKIyMjIFZvbGNhbm8gUGxvdHMKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQpyZXMuZmlsdGVyZWQgJT4lIAogIGdncGxvdChhZXMoeD1sb2cyRm9sZENoYW5nZSwgeT0tbG9nMTAocHZhbHVlKSwgbGFiZWw9cm93bmFtZXMocmVzLmZpbHRlcmVkKSkpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgImJsdWUiLCAicmVkIikpKwogIGdlb21fdGV4dF9yZXBlbCgpCmBgYAogIAojIyMgUnVuIEdlbmUgT250b2xvZ3kKYGBge3IgcnVuIGdlbmUgb250b2xvZ3l9CgpgYGAKCiMjIFJlLXJ1biBERVNlcSB1c2luZyBJQzUwIGFzIGNvbnRpbnVvdXMgdmFyaWFibGUKIyMjIENyZWF0ZSBERVNlcURhdGFTZXQgb2JqZWN0IGRkcwoKYGBge3IgfQpkZHMyIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY291bnRtYXRyaXgyLCBjb2xEYXRhID0gbWV0YWRhdGEsIGRlc2lnbiA9IH4gU3VidHlwZSArIElDNTApCmBgYAojIyMgUHJlLWZpbHRlcmluZwpUaGlzIHN0ZXAgcmVtb3ZlcyBnZW5lcyB3aXRoIGxvdyBleHByZXNzaW9uIHRvIGluY3JlYXNlIG11bHRpcGxlIGNvbXBhcmlzb24gcG93ZXIuCgpgYGB7cn0Ka2VlcCA8LSByb3dTdW1zKGNvdW50cyhkZHMyKSkgPj0gMTAwCmRkczIgPC0gZGRzMltrZWVwLF0KbnJvdyhkZHMyKQpgYGAKCgojIyMgUnVuIERFU2VxMiAKYGBge3IgfQpkZHMyIDwtIERFU2VxKGRkczIpCmBgYAoKIyMjIFByaW50IERFU2VxIHJlc3VsdHMKYGBge3IgfQpyZXMyIDwtIHJlc3VsdHMoZGRzMikKcmVzMgp3cml0ZS5jc3YoYXMuZGF0YS5mcmFtZShyZXMyKSwgZmlsZSA9ICJERVNlcV9JQzUwLmNzdiIpCmBgYAoKIyMjIEZpbHRlciBERVNlcTIgcmVzdWx0cyBmb3Igc2lnbmlmaWNhbnQgZ2VuZXMKRmlsdGVyIHJlcyBmb3IgcGFkaiA8IDAuMDUgYW5kIHxsb2cyRkN8ID49IDEuMgpgYGB7ciB9CnJlcy4yLmZpbHRlcmVkIDwtIGFzLmRhdGEuZnJhbWUocmVzMikgJT4lCiAgZmlsdGVyKHBhZGo8MC4wNSklPiUKICBmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPj0gMS4yIHwgbG9nMkZvbGRDaGFuZ2UgPD0gLTEuMikKcmVzLjIuZmlsdGVyZWQKYGBgCgojIyBEYXRhIFFDCgojIyMgRGF0YSB0cmFuc2Zvcm1hdGlvbiAKCmBgYHtyIH0KdnNkMiA8LSB2c3QoZGRzMikKbWVhblNkUGxvdChhc3NheSh2c2QyKSkKYGBgCgojIyMgUENBIHBsb3QKYGBge3J9CnBjYURhdGEyIDwtIHBsb3RQQ0EodnNkMiwgaW50Z3JvdXA9YygiU3VidHlwZSIsICJQbGF0aW51bVNlbnNpdGl2aXR5IiwiQ2VsbExpbmUiKSwgcmV0dXJuRGF0YT1UUlVFKQpwZXJjZW50VmFyMiA8LSByb3VuZCgxMDAgKiBhdHRyKHBjYURhdGEyLCAicGVyY2VudFZhciIpKQpwY2EyIDwtIGdncGxvdChwY2FEYXRhMiwgYWVzKFBDMSwgUEMyLCBjb2xvcj1TdWJ0eXBlLCBzaGFwZT1QbGF0aW51bVNlbnNpdGl2aXR5LCBsYWJlbD1DZWxsTGluZSkpICsKICBnZW9tX3BvaW50KHNpemU9MykgKwogIGdlb21fdGV4dChoanVzdD0wLCB2anVzdD0wKSArCiAgeGxhYihwYXN0ZTAoIlBDMTogIixwZXJjZW50VmFyMlsxXSwiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIixwZXJjZW50VmFyMlsyXSwiJSB2YXJpYW5jZSIpKSArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBjb2xTY2FsZQpwY2EyCmdnc2F2ZSgicGNhX0lDNTAucGRmIiwgcGNhMikKYGBgCgojIyBEYXRhIHZpc3VhbGl6YXRpb24KCiMjIyBQbG90IEhlYXRtYXAgb2YgdG9wIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcwpgYGB7ciAsIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSA4fQp2c2QyLmRmIDwtYXMuZGF0YS5mcmFtZShhc3NheSh2c2QyKSkKY29sb3IgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJ3aGl0ZSIsICJyZWQiKSkoNDApCmJyZWFrcyA8LSBzZXEoNiwxMixsZW5ndGgub3V0PTQwKSAgCnBoZWF0bWFwKHZzZDIuZGZbcm93bmFtZXMocmVzLjIuZmlsdGVyZWQpLF0sIGxhYmVsc19jb2w9Y29sRGF0YShkZHMyKVssYygiQ2VsbExpbmUiKV0sYW5ub3RhdGlvbl9jb2w9ZGYsIGNvbG9yPWNvbG9yLCBicmVha3M9YnJlYWtzKQpgYGAKCiMjIyBIZWF0bWFwIHdpdGggbWVhbi1jZW50ZXJlZCBkYXRhCmBgYHtyLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD04fQp2c2QyLm1lYW5jZW50ZXIgPC0gYXBwbHkodnNkMi5kZiwgMSwgY2VudGVyX3NjYWxlKQp2c2QyLm1lYW5jZW50ZXIgPC10KHZzZDIubWVhbmNlbnRlcikKY29sbmFtZXModnNkMi5tZWFuY2VudGVyKSA8LSBjb2xuYW1lcyh2c2QyLmRmKQp2c2QyLm1lYW5jZW50ZXIgPC0gYXMuZGF0YS5mcmFtZSh2c2QyLm1lYW5jZW50ZXIpIApjb2xvciA8LSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoMTEsICJQdU9yIikpKDUwKQpteUJyZWFrczIgPC0gYyhzZXEobWluKHZzZDIubWVhbmNlbnRlcltyb3duYW1lcyhyZXMuMi5maWx0ZXJlZCksXSksIDAsIGxlbmd0aC5vdXQ9Y2VpbGluZyg1MC8yKSArIDEpLCAKICAgICAgICAgICAgICBzZXEobWF4KHZzZDIubWVhbmNlbnRlcltyb3duYW1lcyhyZXMuMi5maWx0ZXJlZCksXSkvNTAsIG1heCh2c2QyLm1lYW5jZW50ZXJbcm93bmFtZXMocmVzLjIuZmlsdGVyZWQpLF0pLCBsZW5ndGgub3V0PWZsb29yKDUwLzIpKSkKcGhlYXRtYXAodnNkMi5tZWFuY2VudGVyW3Jvd25hbWVzKHJlcy4yLmZpbHRlcmVkKSxdLCBsYWJlbHNfY29sPWNvbERhdGEoZGRzMilbLGMoIkNlbGxMaW5lIildLCBjb2xvcj1jb2xvciwgYm9yZGVyX2NvbG9yID0gTkEsIGFubm90YXRpb25fY29sID0gZGYsIGJyZWFrcz1teUJyZWFrczIpCmBgYAoKIyMjIFZvbGNhbm8gUGxvdHMKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQpyZXMuMi5maWx0ZXJlZCAlPiUgCiAgZ2dwbG90KGFlcyh4PWxvZzJGb2xkQ2hhbmdlLCB5PS1sb2cxMChwdmFsdWUpLCBsYWJlbD1yb3duYW1lcyhyZXMuMi5maWx0ZXJlZCkpKSArCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsICJibHVlIiwgInJlZCIpKSsKICBnZW9tX3RleHRfcmVwZWwoKQpgYGAKCgoKCgoKIyMjIEhlYXRtYXAgb2YgZ2VuZXMgaW52b2x2ZWQgaW4gY2lzcGxhdGluIHJlc2lzdGFuY2UKUGxvdCBoZWF0bWFwIG9mIGdlbmVzIGFubm90YXRlZCBhcyBpbnZvbHZlZCBpbiBjaXNwbGF0aW4gcmVzaXN0YW5jZSBpbiBQTUlEOiAzNDY0NTk3OApgYGB7ciwgZmlnLmhlaWdodCA9IDQ1LCBmaWcud2lkdGggPSA4fQpyZXNpc3QuZ2VuZXMgPC0gcmVhZC5kZWxpbSgiUmVzaXN0YW5jZUdlbmVzLnR4dCIsIGhlYWRlciA9IEZBTFNFKQpyZXNpc3QuZ2VuZXMgPC0gcmVzaXN0LmdlbmVzJFYxCnBoZWF0bWFwKFRQTS5sb2dbcmVzaXN0LmdlbmVzW3Jlc2lzdC5nZW5lcyAlaW4lIHJvdy5uYW1lcyhUUE0ubG9nKV0sXSwgbGFiZWxzX2NvbD1jb2xEYXRhKGRkcylbLGMoIkNlbGxMaW5lIildLGFubm90YXRpb25fY29sPWRmLCBjb2xvcj1jb2xvclJhbXBQYWxldHRlKGMoIndoaXRlIiwgInJlZCIpKSg1MCkpCmBgYAoKYGBge3J9CnJlczIucmVzaXN0IDwtIHJlczJbcmVzaXN0LmdlbmVzW3Jlc2lzdC5nZW5lcyAlaW4lIHJvdy5uYW1lcyhyZXMyKV0sYygibG9nMkZvbGRDaGFuZ2UiLCJwYWRqIildCnJlczIucmVzaXN0IDwtIGFzLmRhdGEuZnJhbWUocmVzMi5yZXNpc3QpICU+JQogIGZpbHRlcihwYWRqIDwgMC4wNSkKcmVzMi5yZXNpc3QKYGBgCiMjIyBIZWF0bWFwIHdpdGggbWVhbi1jZW50ZXJlZCBkYXRhCmBgYHtyLCBmaWcuaGVpZ2h0PTQ1LCBmaWcud2lkdGg9OH0KbXlCcmVha3MzIDwtIGMoc2VxKG1pbih2c2QubWVhbmNlbnRlcltyZXNpc3QuZ2VuZXNbcmVzaXN0LmdlbmVzICVpbiUgcm93Lm5hbWVzKHZzZC5tZWFuY2VudGVyKV0sXSksIDAsIGxlbmd0aC5vdXQ9Y2VpbGluZyg1MC8yKSArIDEpLCAKICAgICAgICAgICAgICBzZXEobWF4KHZzZC5tZWFuY2VudGVyW3Jlc2lzdC5nZW5lc1tyZXNpc3QuZ2VuZXMgJWluJSByb3cubmFtZXModnNkLm1lYW5jZW50ZXIpXSxdKS81MCwgbWF4KHZzZC5tZWFuY2VudGVyW3Jlc2lzdC5nZW5lc1tyZXNpc3QuZ2VuZXMgJWluJSByb3cubmFtZXModnNkLm1lYW5jZW50ZXIpXSxdKSwgbGVuZ3RoLm91dD1mbG9vcig1MC8yKSkpCnBoZWF0bWFwKHZzZC5tZWFuY2VudGVyW3Jlc2lzdC5nZW5lc1tyZXNpc3QuZ2VuZXMgJWluJSByb3cubmFtZXModnNkLm1lYW5jZW50ZXIpXSxdLCBsYWJlbHNfY29sPWNvbERhdGEoZGRzKVssYygiQ2VsbExpbmUiKV0sYW5ub3RhdGlvbl9jb2w9ZGYsIGNvbG9yPWNvbG9yLCBib3JkZXJfY29sb3IgPSBOQSwgYnJlYWtzPW15QnJlYWtzMykKYGBgCgoKCiMjIFBhY2thZ2UgdmVyc2lvbnMKRmlndXJlIG91dCBob3cgdG8gcHJpbnQgYWxsIHBhY2thZ2UgdmVyc2lvbnMgdXNlZC4K